<template>

  <div id="mapCard" v-loading="loading">
    <!-- 地图 -->
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800.0 600.0" :id="id" :height="mapHeight" width="100%"></svg>

    <!-- 地图放大缩小按钮 -->
    <div id="btn-area">
      <el-button id="scale-up" type="primary" @click="svgPanZoomScaleUp" icon="el-icon-plus"></el-button>

      <el-button id="scale-down" type="primary" @click="svgPanZoomScaleDown" icon="el-icon-minus"></el-button>

      <el-button id="reset-btn" type="primary" @click="svgPanZoomReset" icon="el-icon-location-outline"></el-button>
    </div>
    <!-- 地图放大缩小按钮 -->

    <!-- agv左侧信息面板 -->
    <div class="agvInfo" v-show="isShow">
      <div class="info-title">
        <div class="agv_title">{{ agvClicked }}</div>
        <div @click="closeInfo"><i class="el-icon-circle-close"></i></div>
      </div>
      <div class="agv_list">
        <div>AGV编号: {{ agvClickedInfo.id }}</div>
        <div>状态: {{ agvClickedInfo.status === 0 ? 'Run' : agvClickedInfo.status === 1 ? 'Idle' : 'Down' }}</div>
        <div>当前电量: {{ agvClickedInfo.powerPercent }}</div>
        <div>异常原因: {{ agvClickedInfo.error }}</div>
      </div>
    </div>
    <!-- agv左侧信息面板 -->

  </div>
</template>

<script>
import * as d3 from '../assets/js/d3.min'
import '../assets/js/jquery.svg.pan.zoom'
// import '../assets/js/agv'

export default {
  data() {
    return {
      viewBoxInitWidth: 0,
      viewBoxInitHeight: 0,
      minX: null,
      minY: null,
      maxX: null,
      maxY: null,
      scale: null,
      mapObj: null,
      svgPanZoom: null,
      svgNS: 'http://www.w3.org/2000/svg',
      oParent: null,
      oSvg: null,
      agvInfoClick: null,
      agvListDate: [],
      // map height
      mapHeight: window.innerHeight * 0.75,
      // map width
      mapWidth: window.innerWidth,
      loading: true,
      agvGreenPath: {},
      // 计时器
      timer: [],
      mapData: [],
      // 上次浏览时间
      lastBrowseDate: 0,
      // 清除timer延时器
      lastBrowseTimeouter: [],
      hiddenTimer: [],
      browseInterval: 1000 * 60 * 5,
      agvClickedInfo: {},
      isShow: false,
      agvClicked: '',
      id: 'svgMap',
      MapHref: require('../assets/img/map.svg'),
      agv: [],
    }
  },
  // props: {
  //   id: {
  //     type: String,
  //     default: null,
  //     require: true
  //   },
  //   agv: {
  //     typeof: Array,
  //     default: null,
  //     require: true
  //   },
  //   map: {
  //     typeof: Array,
  //     default: null,
  //     require: true
  //   }
  // },
  watch: {
    // 监听到父组件传递过来的数据后，加工一下，
    // 存到data中去，然后在页面上使用
    // map(newnew) {
    //   console.log(newnew);
    //   this.mapData = newnew
    //   newnew && this.mapInit()
    // },
    // agv(newnew, oldold) {
    //   this.agvList = newnew
    //   newnew && this.mapInit()
    // }
  },
  created() {},
  mounted() {
    // console.log(map);
    // setTimeout(() => {
    this.mapInit()
    // }, 1000)
    this.checkDocVis()
  },
  beforeDestroy() {
    this.cleanTimer()
    this.cleanHiddenTimer()
  },
  methods: {
    // 检测 document visible
    checkDocVis() {
      document.onvisibilitychange = () => {
        // let browseInterval = 1000 * 60 * 30
        // let browseInterval = 1000 * 60 * 5
        const browseInterval = this.browseInterval

        if (document.visibilityState == 'visible') {
          if (this.lastBrowseTimeouter.length > 0) {
            for (let i = 0; i < this.lastBrowseTimeouter.length; i++) {
              clearInterval(this.lastBrowseTimeouter.pop())
            }
            this.cleanHiddenTimer()
          }

          if (window.sessionStorage.mapDataSwitch == 'off') {
            window.sessionStorage.mapDataSwitch = 'on'
            window.location.reload()
          }
        } else {
          if (window.sessionStorage.mapDataSwitch == 'off') {
            this.cleanTimer()
          }
          this.lastBrowseTimeouter.push(
            setTimeout(() => {
              this.cleanTimer()
              window.sessionStorage.mapDataSwitch = 'off'
            }, browseInterval)
          )
          this.lastBrowseTimeouter.push(
            setTimeout(() => {
              window.location.reload()
            }, browseInterval * 2)
          )
        }
      }
    },
    closeInfo() {
      this.isShow = false
    },
    agvClick(agv) {
      this.agvInfoCardUpdate(agv)
      this.isShow = true
    },
    agvInfoCardUpdate(agv) {
      this.agvClicked = agv.id
      this.agvClickedInfo = agv
    },
    // 地图初始化
    mapInit() {
      this.oSvg = document.getElementById(this.id)
      setTimeout(() => {
        this.getMapInfo()
        this.loading = false
      }, 1000)
      setTimeout(() => {
        if (window.sessionStorage.mapDataSwitch == 'off') {
          this.cleanTimer()
          this.hiddenTimer.push(
            setInterval(() => {
              if (document.visibilityState == 'hidden') {
                window.location.reload()
              }
            }, this.browseInterval * 2.1)
          )
        }
      }, 5000)
    },
    // agv实时移动
    agvMoveRT() {
      this.getAgvState()
      this.timer.push(
        setInterval(() => {
          this.getAgvState()
        }, 3000)
      )
    },
    // 获取agvList信息
    async getAgvState () {
      const { data: res } = await this.$http.get('/api/getRobotPointInfo')
      this.agvListDate = res
      const run = res.filter(v => v.status === 0).length
      const idle = res.filter(v => v.status === 1).length
      const down = res.filter(v => v.status === 2).length
      this.$emit('status', run, idle, down)
      this.agvMove(this.mapData, this.agvListDate, this.oSvg)
    },
    // 获取地图信息
    async getMapInfo() {
      const { data: res } = await this.$http.get('/api/getMapPointInfo')
      this.mapData = res
      this.mapData.push({
        id: 'Point-0001',
        x: -12.267,
        y: 44.028,
      })
      this.mapData.push({
        id: 'Point-0002',
        x: 56.965,
        y: 10.412,
      })
      await this.handleYAxis()
      await this.createMap(this.mapData, this.oSvg, this.MapHref)
      // eslint-disable-next-line no-undef
      this.svgPanZoom = await $('#' + this.id).svgPanZoom()
      setTimeout(() => {
        this.agvMoveRT()
      },1000)
      // this.agvMove(this.mapData, this.agv, this.oSvg)
    },
    // 清除timer
    cleanTimer() {
      for (let i = 0; i < this.timer.length; i++) {
        clearInterval(this.timer.pop())
      }
    },
    // 清除hiddenTimer
    cleanHiddenTimer() {
      for (let i = 0; i < this.hiddenTimer.length; i++) {
        clearInterval(this.hiddenTimer.pop())
      }
    },
    // svg ↑
    svgPanZoomScaleUp() {
      const vBWidth = Number(
        document.getElementById(this.id).getAttribute('viewBox').split(' ')[2]
      )

      if (vBWidth >= this.viewBoxInitWidth / 4) {
        this.svgPanZoom.zoomIn()
      }
    },
    // svg ↓
    svgPanZoomScaleDown() {
      this.svgPanZoom.zoomOut()
    },
    // svg ♨
    svgPanZoomReset() {
      this.svgPanZoom.reset()
    },

    createSvgTag(tag, objAttr) {
      var oTag = document.createElementNS(this.svgNS, tag)
      for (var attr in objAttr) {
        oTag.setAttribute(attr, objAttr[attr])
      }
      return oTag
    },
    handleYAxis() {
      const newMapData = this.mapData.map((point) => {
        point.y = -point.y
        return point
      })
      this.mapData = newMapData
    },
    structmapData() {
      const ret = {}
      this.mapData.forEach((point) => {
        const pointName = point.id
        ret[pointName] = point
      })
      return ret
    },

    getScale(mapData) {
      const winX = window.outerWidth
      const winY = window.outerHeight
      let maxX = null
      let maxY = null
      let minX = null
      let minY = null

      mapData.forEach((point) => {
        if (point.x > maxX || maxX == null) {
          maxX = point.x
        }
        if (point.y > maxY || maxY == null) {
          maxY = point.y
        }
        if (point.x < minX || minX == null) {
          minX = point.x
        }
        if (point.y < minY || minY == null) {
          minY = point.y
        }
      })

      if (minX == maxX && minX != null) {
        maxX += 10
      }

      if (minY == maxY && minY != null) {
        maxY += 10
      }

      const scale1 = winX / Math.abs(maxX - minX)
      const scale2 = winY / Math.abs(maxY - minY)
      const scaleRes = scale1 > scale2 ? scale2 : scale1

      return { scale: scaleRes, minX: minX, minY: minY, maxX: maxX, maxY: maxY }
    },

    switchAngle(radian) {
      return (radian * 180) / Math.PI
    },

    switchRadian(angle) {
      return (angle * Math.PI) / 180
    },

    objectFocus(point, oSvg, pointSize, pointFontSize, scale) {
      const pointStrokeColor = '#98999c'
      // let pointInfoFontColor = '#804000'
      const pointInfoFontColor = '#804000'
      const pointFontBgColor = '#d5d5d5'
      const pointFontBgStrokeColor = '#383838'

      // let pointFontSize = pointFontSize
      const pointSelect = document.getElementById(point.id)
      if (pointSelect != null) {
        pointSelect.setAttribute('stroke', pointStrokeColor)
        pointSelect.setAttribute('stroke-width', pointFontSize / 10)
        pointSelect.setAttribute('stroke-opti', 0.8)
      }

      const fontTagIsExist = document.getElementById(point.id + 'Info')
      if (fontTagIsExist == null) {
        // let pointNumIndex = point.currentPoint.indexOf('-')
        // let realPointNum = Number(point.currentPoint.substring(pointNumIndex +1)) + 1000000000
        const pointFontInitX = point.x * scale
        const pointFontInitY = point.y * scale - pointSize - pointFontSize
        const pointFontTag = this.createSvgTag('text', {
          id: point.id + 'Font',
          class: 'pointFontTag',
          x: pointFontInitX,
          y: pointFontInitY,
          'font-size': pointFontSize,
          fill: pointInfoFontColor,
          'text-anchor': 'middle',
          // 'style': 'cursor: pointer;',
        })

        pointFontTag.innerHTML = point.id

        const pointFontBgHeight = pointFontSize * 1.8
        const pointFontBgWidth = String(point.id).length * pointFontSize * 0.8
        const pointFontBgInitX = point.x * scale - pointFontBgWidth / 2
        const pointFontBgInitY =
          point.y * scale -
          pointFontBgHeight / 2 -
          pointSize -
          pointFontSize * 1.3
        const pointFontBgTag = this.createSvgTag('rect', {
          id: point.id + 'FontBg',
          class: 'pointFontBgTag',
          x: pointFontBgInitX,
          y: pointFontBgInitY,
          width: pointFontBgWidth,
          height: pointFontBgHeight,
          rx: (pointFontSize * 2) / 5,
          ry: (pointFontSize * 2) / 5,
          fill: pointFontBgColor,
          stroke: pointFontBgStrokeColor,
          opacity: 0.8,
          'stroke-width': pointFontSize / 10,
        })

        const pointInfoTag = this.createSvgTag('g', {
          id: point.id + 'Info',
          style: 'cursor: pointer;',
        })

        pointInfoTag.appendChild(pointFontBgTag)
        pointInfoTag.appendChild(pointFontTag)

        oSvg.appendChild(pointInfoTag)
      }
    },

    objectBlur(point, oSvg) {
      const pointSelect = document.getElementById(point.id)
      // console.log(point);
      if (pointSelect != null) {
        pointSelect.removeAttribute('stroke')
        pointSelect.removeAttribute('stroke-width')
        pointSelect.removeAttribute('stroke-opti')
      }
      // console.log(pointSelect);
      const fontTag = document.getElementById(point.id + 'Info')
      if (fontTag != null) {
        oSvg.removeChild(fontTag)
      }
    },

    agvFocus(agv, oSvg) {
      const agvSelect = document.getElementById(agv.id)
      const agvInfoSelect = document.getElementById('Info' + agv.id)
      if (agvSelect != null && agvInfoSelect != null) {
        oSvg.removeChild(agvSelect)
        oSvg.removeChild(agvInfoSelect)
      }
      oSvg.appendChild(agvSelect)
      oSvg.appendChild(agvInfoSelect)
    },

    setScaleAndViewBox(mapData, oSvg) {
      const getScaleRes = this.getScale(mapData)
      this.scale = getScaleRes.scale
      this.minX = getScaleRes.minX
      this.minY = getScaleRes.minY
      this.maxX = getScaleRes.maxX
      this.maxY = getScaleRes.maxY

      // 正中间
      // const oSvgWidth = Math.abs(this.maxX - this.minX) * this.scale * 1.1
      // const oSvgHeight = Math.abs(this.maxY - this.minY) * this.scale * 1.1
      // const oSvgX = (this.minX) * this.scale - (oSvgWidth * 0.05)
      // const oSvgY = (this.minY) * this.scale - (oSvgHeight * 0.05)

      // 偏左&放大
      const svgClientWidth = oSvg.clientWidth
      const svgClientHeight = oSvg.clientHeight
      const oSvgWidth = Math.abs(this.maxX - this.minX) * this.scale
      const oSvgHeight = Math.abs(this.maxY - this.minY) * this.scale
      const oSvgX =
        this.minX * this.scale + oSvgWidth * 0.005 + svgClientWidth * 0.001
      const oSvgY =
        this.minY * this.scale + oSvgHeight * 0.005 + svgClientHeight * 0.001
      // const oSvgX = svgClientWidth * 0.21
      // const oSvgY = svgClientHeight * 0.13

      const viewBoxAttr =
        oSvgX + ' ' + oSvgY * 1.1 + ' ' + oSvgWidth + ' ' + oSvgHeight * 1.2
      this.viewBoxInitWidth = oSvgWidth
      this.viewBoxInitHeight = oSvgHeight
      oSvg.setAttribute('viewBox', viewBoxAttr)
    },
    createMap(mapData, oSvg, MapHref) {
      const pointSize = 8
      let pointColor = '#9a7fd1'
      const pointOpacity = 1
      const pointFontSize = 10
      let backgroundMapHref = null

      try {
        backgroundMapHref = MapHref
      } catch (error) {
        console.log(error)
      }

      if (this.mapObj == null) {
        this.mapObj = this.structmapData(mapData)
      }
      if (this.scale == null) {
        this.setScaleAndViewBox(mapData, oSvg)
      }
      const scale = this.scale
      const mapObj = this.mapObj

      // 底图绘制
      if (
        mapObj['Point-0001'] != null &&
        mapObj['Point-0002'] != null &&
        backgroundMapHref != null
      ) {
        const p1 = mapObj['Point-0001']
        const p2 = mapObj['Point-0002']
        const backgroundMapX = p1.x * scale
        const backgroundMapY = -Math.abs(p1.y) * scale
        const backgroundMapWidth = Math.abs(p2.x - p1.x) * scale
        const backgroundMapHeight = Math.abs(p2.y - p1.y) * scale
        const backgroundMapTag = this.createSvgTag('image', {
          id: 'backgroundMap',
          // 'class':'agvTag',
          x: backgroundMapX,
          y: backgroundMapY,
          width: backgroundMapWidth,
          height: backgroundMapHeight,
          // 'style': 'cursor: pointer;',
          href: backgroundMapHref,
          // 'href':{'baseVal':"./img/agv.png"},
        })
        oSvg.appendChild(backgroundMapTag)
      } else {
        // oSvg.style.background = '#303133'
        pointColor = '#171746'
      }
      // point绘制
      this.mapData.forEach((point) => {
        if (point.id === 'Point-0001' || point.id === 'Point-0002') {
          return false
        }
        const pointTag = this.createSvgTag('rect', {
          id: point.id,
          class: 'pointTag',
          x: point.x * scale - (1 / 2) * pointSize,
          y: point.y * scale - (1 / 2) * pointSize,
          fill: pointColor,
          width: pointSize,
          height: pointSize,
          opacity: pointOpacity,
          // 'stroke':"black",
          // 'stroke-width':"1"
          style: 'cursor: pointer;',
        })
        pointTag.onmouseenter = () => {
          this.objectFocus(point, oSvg, pointSize, pointFontSize, scale)
        }

        pointTag.onmouseleave = () => {
          this.objectBlur(point, oSvg)
        }

        oSvg.appendChild(pointTag)
      })
    },

    agvMove(mapData, agvListDate, oSvg) {
      const agvImgWidth = 60
      const agvImgHeight = 32
      const agvFontSize = 10
      // const agvImg = './map_resource/img/keriAGV.png'
      const agvImg = require('../assets/img/AGV000.png')
      const agvFontColor = '#804000'
      const agvFontBgColor = '#d5d5d5'
      const agvFontBgOpacity = 0.8
      const agvFontStrokeColor = '#383838'

      if (this.mapObj == null) {
        this.mapObj = this.structmapData(mapData)
      }
      if (this.scale == null) {
        this.setScaleAndViewBox(mapData, oSvg)
      }
      const scale = this.scale
      // const mapObj = this.mapObj

      const agvImgCEdge = Math.sqrt(
        Math.pow(agvImgHeight, 2) + Math.pow(agvImgWidth, 2)
      )

      agvListDate.forEach((agv) => {
        let agvAngle = 0
        const agvSysAngle = agv.robotAngle
        // 角度为空则自动判断
        if (agvSysAngle != null) {
          agvAngle = this.switchRadian(Number(agvSysAngle))
        }
        const agvX = agv.x * scale
        const agvY = -agv.y * scale
        const fontX = agv.x * scale
        const fontY =
          -agv.y * scale -
          Math.abs(Math.sin(agvAngle - Math.atan2(agvImgHeight, agvImgWidth))) *
            (agvImgCEdge / 2)
        const agvOnSvg = document.getElementById('agv' + agv.id)
        if (agvOnSvg == null) {
          const agvImgTag = this.createSvgTag('image', {
            id: agv.id + 'Img',
            class: 'agvImgTag',
            x: -agvImgWidth / 2,
            y: -agvImgHeight / 2,
            width: agvImgWidth,
            height: agvImgHeight,
            style: 'cursor: pointer;',
            href: agvImg,
            // 'href':{'baseVal':"./img/agv.png"},
          })

          const agvBgTag = this.createSvgTag('circle', {
            id: 'Bg' + agv.id,
            class: 'agvBgTag',
            // cx: -agvImgWidth / 2,
            // cy: -agvImgHeight / 2,
            r: agvImgWidth * 2,
            fill: 'none',
            // stroke:"red",
            // 'stroke-width':"5",
            // 'stroke-opacity':"0.1",
          })

          const agvTag = this.createSvgTag('g', {
            id: 'agv' + agv.id,
            style: 'cursor: pointer;',
          })

          agvTag.appendChild(agvBgTag)
          agvTag.appendChild(agvImgTag)

          const agvFontInitX = 0
          const agvFontInitY = -agvFontSize * 1.5
          const agvFontTag = this.createSvgTag('text', {
            id: agv.id + 'Font',
            class: 'agvFontTag',
            x: agvFontInitX,
            y: agvFontInitY,
            'font-size': agvFontSize,
            fill: agvFontColor,
            'text-anchor': 'middle',
            // 'style': 'cursor: pointer;',
          })

          agvFontTag.innerHTML = agv.id

          const agvFontBgHeight = agvFontSize * 2
          // let agvFontBgWidth = agvFontSize * 4.5
          const agvFontBgWidth = String(agv.id).length * agvFontSize
          const agvFontBgInitX = -agvFontBgWidth / 2
          const agvFontBgInitY = -agvFontBgHeight / 2 - agvFontSize * 2
          const agvFontBgTag = this.createSvgTag('rect', {
            id: agv.id + 'FontBg',
            class: 'agvFontBgTag',
            x: agvFontBgInitX,
            y: agvFontBgInitY,
            width: agvFontBgWidth,
            height: agvFontBgHeight,
            rx: (agvFontSize * 2) / 5,
            ry: (agvFontSize * 2) / 5,
            fill: agvFontBgColor,
            opacity: agvFontBgOpacity,
            stroke: agvFontStrokeColor,
            'stroke-width': agvFontSize / 10,
          })

          const agvInfoTag = this.createSvgTag('g', {
            id: 'Info' + agv.id,
            style: 'cursor: pointer;',
          })

          agvInfoTag.appendChild(agvFontBgTag)
          agvInfoTag.appendChild(agvFontTag)

          oSvg.appendChild(agvTag)
          oSvg.appendChild(agvInfoTag)
          agvTag.onclick = () => {
            this.agvClick(agv)
          }

          agvInfoTag.onclick = () => {
            this.agvClick(agv)
          }

          d3.select('#agv' + agv.id)
            // .transition()
            // .duration(1000)
            .attr(
              'transform',
              `translate(${agvX},${agvY})  rotate(${-this.switchAngle(
                agvAngle
              )})`
            )

          d3.select('#' + 'Info' + agv.id)
            // .transition()
            // .duration(1000)
            .attr('transform', `translate(${fontX},${fontY})`)

          if (agv.status === 0) {
            d3.select('#' + 'Bg' + agv.id).attr(
              'style',
              'animation: aniGreen 3s linear infinite;'
            )
          } else if (agv.status === 1) {
            d3.select('#' + 'Bg' + agv.id).attr(
              'style',
              'animation: aniYellow 3s linear infinite;'
            )
          } else if (agv.status === 2) {
            d3.select('#' + 'Bg' + agv.id).attr(
              'style',
              'animation: aniRed 3s linear infinite;'
            )
          }
        } else {
          // agv移动
          d3.select('#agv' + agv.id)
            .transition()
            .duration(3000)
            .attr(
              'transform',
              `translate(${agvX},${agvY})  rotate(${-this.switchAngle(
                agvAngle
              )})`
            )

          // Info移动
          d3.select('#' + 'Info' + agv.id)
            .transition()
            .duration(3000)
            .attr('transform', `translate(${fontX},${fontY})`)

          if (agv.status === 0) {
            d3.select('#' + 'Bg' + agv.id).attr(
              'style',
              'animation: aniGreen 3s linear infinite;'
            )
          } else if (agv.status === 1) {
            d3.select('#' + 'Bg' + agv.id).attr(
              'style',
              'animation: aniYellow 3s linear infinite;'
            )
          } else if (agv.status === 2) {
            d3.select('#' + 'Bg' + agv.id).attr(
              'style',
              'animation: aniRed 3s linear infinite;'
            )
          }
        }

        if (this.isShow == true && this.agvClicked === agv.id) {
          this.agvInfoCardUpdate(agv)
        }
      })
    },
  },
}
</script>

<style lang="less" scoped>
#mapCard {
  position: relative;
}
/deep/ .el-button--mini,
.el-button--mini.is-round {
  padding: 2px 5px;
  i {
    font-size: 10px;
  }
}

#btn-area {
  padding: 0px;
  position: absolute;
  left: 2%;
  bottom: 2%;
  background-color: rgba(0, 0, 0, 0);
  z-index: 5;
  div {
    padding: 2px;
  }
}
.agvInfo {
  position: absolute;
  right: 2%;
  top: 3%;
  width: 300px;
  height: 300px;
  background-color: rgba(0, 101, 252, 0.6);
  z-index: 100000;
  .info-title {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px;
    .agv_title {
      font-size: 26px;
      color: #fff;
      font-weight: bold;
    }
    i {
      font-size: 26px;
      color: #fff;
      cursor: pointer;
    }
  }
  .agv_list {
    div {
      padding: 5px;
      font-size: 20px;
      color: #fff;
    }
  }
}
</style>
